package com.jsh.erp.service.examine;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jsh.erp.constants.BusinessConstants;
import com.jsh.erp.constants.ExceptionConstants;
import com.jsh.erp.datasource.entities.*;
import com.jsh.erp.datasource.mappers.ExamineMapper;
import com.jsh.erp.exception.BusinessRunTimeException;
import com.jsh.erp.service.depotHead.DepotHeadService;
import com.jsh.erp.service.depotItem.DepotItemService;
import com.jsh.erp.service.sequence.SequenceService;
import com.jsh.erp.service.todoTask.TodoTaskService;
import com.jsh.erp.service.user.UserService;
import com.jsh.erp.utils.Constants;
import com.jsh.erp.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author gonge
 */
@Service
@Slf4j
public class ExamineServiceImpl extends ServiceImpl<ExamineMapper, Examine> implements ExamineService {
    @Resource
    private ExamineMapper examineMapper;

    @Resource
    private UserService userService;

    @Resource
    private ExamineItemService examineItemService;
    @Resource
    private DepotHeadService depotHeadService;
    @Resource
    private DepotItemService depotItemService;
    @Resource
    private HttpServletRequest request;
    @Resource
    private TodoTaskService todoTaskService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createExamine(JSONObject obj, HttpServletRequest request) throws Exception {
        //examine and depotHead and audit
        Examine examine = JSON.parseObject(obj.getJSONObject("info").toJSONString(), Examine.class);
        if(StringUtil.isEmpty(examine.getPurchaseOrderNumber())){
            throw new BusinessRunTimeException(ExceptionConstants.PURCHASE_EXAMINE_NULL_CODE,ExceptionConstants.PURCHASE_EXAMINE_Null_MSG);
        }
        DepotHead depotHead = depotHeadService.getDepotHeadByNumber(examine.getPurchaseOrderNumber());
        if(ObjectUtils.isEmpty(depotHead)){
            throw new BusinessRunTimeException(ExceptionConstants.PURCHASE_EXAMINE_NULL_CODE,ExceptionConstants.PURCHASE_EXAMINE_Null_MSG);
        }else{
            examine.setSaleOrderNumber(depotHead.getLinkNumber());
        }
        //Get Details
        JSONArray jsonArray = obj.getJSONArray("rows");
        List<ExamineItem> examineItemList = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject row = jsonArray.getJSONObject(i);
            ExamineItem examineItem = new ExamineItem();
            examineItem.setMaterialId(row.getLong("id"));
            examineItem.setOriginalNumber(row.getLong("preNumber"));
            examineItem.setBygoneNumber(row.getLong("examineNumber"));
            examineItem.setExamineQuantity(row.getLong("preNumber"));
            examineItem.setUnqualifiedQuantity(row.getLong("unqualifiedQuantity"));
            examineItem.setRemark(row.getString("remark"));
            examineItemList.add(examineItem);
        }
        //Audit and sum
        boolean verify  = true;
        for (ExamineItem item : examineItemList){
            // 质检数量+已检查数量不能大于原数量,并且不合格数量不能大于质检数量。
            if((item.getExamineQuantity()+item.getBygoneNumber()) > item.getOriginalNumber()){
                throw new BusinessRunTimeException(ExceptionConstants.PURCHASE_EXAMINE_GREATER_CODE,ExceptionConstants.PURCHASE_EXAMINE_GREATER_MSG);
            }else if(item.getUnqualifiedQuantity().compareTo(item.getExamineQuantity())>0){
                throw new BusinessRunTimeException(ExceptionConstants.PURCHASE_REJECT_GREATER_CODE,ExceptionConstants.PURCHASE_REJECT_GREATER_MSG);
            }
            if( (item.getExamineQuantity()+item.getBygoneNumber())  != item.getOriginalNumber()  ){
                verify = false;
            }
            examine.setUnqualifiedQuantity((ObjectUtils.isEmpty(examine.getUnqualifiedQuantity())?0:examine.getUnqualifiedQuantity())+item.getUnqualifiedQuantity());
            examine.setExamineQuantity((ObjectUtils.isEmpty(examine.getExamineQuantity())?0:examine.getExamineQuantity())+item.getExamineQuantity());
        }
        //add examine
        examine.setCreatedId(userService.getUserId(request));
        examine.setInspectorId(userService.getUserId(request));
        examine.setQualityStatus(examine.getUnqualifiedQuantity() > 0 ? 0 : 1);
        int result = examineMapper.insert(examine);
        if(result<=0){
            throw new BusinessRunTimeException(ExceptionConstants.PURCHASE_EXAMINE_ADD_ERROR_CODE,ExceptionConstants.PURCHASE_EXAMINE_ADD_ERROR_MSG);
        }
        //Unify set id and update depotItem
        for (ExamineItem item : examineItemList) {
            item.setExamineId(examine.getId());
            DepotItem depotItem = depotItemService.getDepotItem(item.getMaterialId());
            depotItem.setExamineNumber(depotItem.getExamineNumber()+item.getExamineQuantity());
            depotItemService.updateDepotItemWithObj(depotItem);
        }
        //add examineItem
        boolean saveBatch = examineItemService.saveBatch(examineItemList);
        if(!saveBatch){
            throw new BusinessRunTimeException(ExceptionConstants.PURCHASE_EXAMINE_ADD_ERROR_CODE,ExceptionConstants.PURCHASE_EXAMINE_ADD_ERROR_MSG);
        }
        //change depotHead status
        result = depotHeadService.updExamineStatus(verify ? BusinessConstants.BILLS_STATUS_QUALITY_OK : BusinessConstants.BILLS_STATUS_QUALITY, depotHead.getId());
        if(result<=0){
            throw new BusinessRunTimeException(ExceptionConstants.PURCHASE_EXAMINE_ADD_ERROR_CODE,ExceptionConstants.PURCHASE_EXAMINE_ADD_ERROR_MSG);
        }

        //发送信息推送
        DepotHead head = depotHeadService.getDepotHeadByNumber(examine.getPurchaseOrderNumber());
        head.setTurn(examine.getTurn());
        todoTaskService.insertTodoTask(head, Constants.TURN,request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void verifyExamineStatus(DepotHead depotHead) throws Exception {
        /**
         * 采购质检
         * 1.在新增采购订单的时候就确认是否为质检单。（默认为否）
         * 2.如果是质检单，那么在采购入库的时候是不能直接入库的，需提示还未创建质检单，请质检完成后再入库。（不过一般没有创建质检单的采购单在入库时不可见）
         * 3.当来货单据做完质检单后，采购入库时就可以选择对应的采购质检单。（详细表明质检单）
         * 4.选择对应单据后自动关联对应已经创建的质检单（还未入库的质检单），并提示已关联对应质检单质检数据。
         * 5.保存单据的时候把之前创建的质检单标注为已入库（如果质检单已质检数量等于采购数量那么将质检状态改为以检并入库）
         * 6.当入库完成后也就到了最难的一部分，采购退货 如果按照正常流程设计那我们是还需要一个质检退货的，但是太麻烦了
         *   我做了一个专门的退货仓库，当第五步完成的时候自动把不合格的数量做成入库单加入到退货仓库，然后等用户在退货中选择对应入库单据退货。
         * */
        //判断是否关联采购订单
        if(StringUtil.isEmpty(depotHead.getLinkNumber())){
            return;
        }
        //1.根据number查询数据
        DepotHead head = depotHeadService.getDepotHead(depotHead.getLinkNumber());
        //2.根据head判断是否需要质检
        if(head.getIsExamine()==0){
            return;
        }
        //3.需要质检的单据 额外处理
        List<DepotItemVo4WithInfoEx> detailList = depotItemService.getDetailList(head.getId());
            //3.1.得到采购商品总数量
        BigDecimal sum = BigDecimal.ZERO;
        for (DepotItemVo4WithInfoEx infoEx : detailList) {
            sum = sum.add(infoEx.getOperNumber());
        }
            //3.2.得到已质检的总数量
        Long sum2 = examineItemService.getExamineNumber(head.getDefaultNumber());
        //4.判断
        if(sum.intValue() == sum2.intValue()){
            //4.1.修改采购订单状态为已采购
            head.setPurchaseStatus("2");
            head.setExamineStatus(2);
            depotHeadService.updateDepotHead(JSON.parseObject(JSON.toJSONString(head)),request);
        }
        //改动目前采购单的所有质检单状态。
        UpdateWrapper<Examine> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("purchase_order_number", head.getDefaultNumber()).set("return_reason",0 );
        examineMapper.update(null,updateWrapper);
    }
}